/*
 * Menu.java
 * Created on December 20, 2007, 1:05 AM by Clinton Nolan
 *
 * A menu in the menu system, contains data for display and methods for display and control
 */

package MenuSystem;

import java.awt.*;
import javax.swing.*;
import java.awt.image.*;
import java.util.*;
import ScreenSystem.*;
import LuaSystem.LuaEngine;
import org.keplerproject.luajava.*;
import java.io.*;
import java.util.*;

public class GameMenu extends Screen{
    //data section
    protected String name;  //the menu's name
    protected int x;        //the x position of the menu
    protected int y;        //the y position of the menu
    
    //items
    LinkedList<GameMenuItem> items;     //the items in the menu in display order
    Hashtable<String,GameMenuItem> itemtable;  //the items in the menu in searchable order
    Hashtable<String,ControlNode> control;    //the control nodes
    
    //current control node
    ControlNode current;
    
    //Creates a new blank instance of a display-only Menu at x,y
    public GameMenu(int xp, int yp){
        name = null;
        x = xp;
        y = yp;
        
        items = new LinkedList<GameMenuItem>();
        itemtable = new Hashtable<String,GameMenuItem>();
        control = new Hashtable<String,ControlNode>();
    }
    
    //Creates a new blank instance of a display-only Menu called name at x,y
    public GameMenu(int xp, int yp, String n){
        name = n;
        x = xp;
        y = yp;
        
        items = new LinkedList<GameMenuItem>();
        itemtable = new Hashtable<String,GameMenuItem>();
        control = new Hashtable<String,ControlNode>();
    }
    
    //set the current control node
    public void setActiveControlNode(ControlNode n){
        current = n;
    }
    
    //adds an item to the menu given a MenuItem object
    public void addMenuItem(String n, GameMenuItem gmi){
        items.add(gmi);
        itemtable.put(n,gmi);
    }
    
    //removes a specific item from the menu given its MenuItem object
    /*public void removeMenuItem(GameMenuItem gmi){
        items.remove(gmi);
    }*/
    
    //removes a specific item from the menu given its name
    public void removeMenuItem(String n){
        GameMenuItem gmi = itemtable.get(n);
        if(gmi != null){
            items.remove(gmi);
        }else{
            System.err.println("Could not remove MenuItem "+n);
        }
    }
    
    public GameMenuItem getMenuItem(String n){
        return itemtable.get(n);
    }
    
    //adds a control node
    public void addControlNode(String n, ControlNode cn){
        control.put(n,cn);
        if(current == null){
            current = cn;
        }
    }
    
    //removes a control node
    public void removeControlNode(ControlNode cn){
        control.remove(cn);
    }
    
    //gets a specific control node
    public ControlNode getControlNode(String n){
        return control.get(n);
    }
    
    //draws the menu to the given graphical context
    public void draw(Graphics2D g, JComponent screen){
        ListIterator<GameMenuItem> ptr = items.listIterator();
        while(ptr.hasNext()){
            ptr.next().draw(g,x,y,screen);
        }
    }
    
    //handle key presses
    public void keyPressUp(){
        handleKeypress("U");
    }
    public void keyPressDown(){
        handleKeypress("D");
    }
    public void keyPressLeft(){
        handleKeypress("L");
    }
    public void keyPressRight(){
        handleKeypress("R");
    }
    public void keyPressB1(){
        handleKeypress("1");
    }
    public void keyPressB2(){
        handleKeypress("2");
    }
    public void keyPressB3(){
        handleKeypress("3");
    }
    public void keyPressB4(){
        handleKeypress("4");
    }
    public void keyPressB5(){
        handleKeypress("5");
    }
    public void keyPressB6(){
        handleKeypress("6");
    }
    public void keyPressB7(){
        handleKeypress("7");
    }
    public void keyPressB8(){
        handleKeypress("8");
    }
    public void keyPressB9(){
        handleKeypress("9");
    }
    public void keyPressB10(){
        handleKeypress("10");
    }
    
    //handle a keypress given the correct key string
    public void handleKeypress(String key){
        if(current == null){
            System.err.println("There is no active control node!");
        }
        KeyDef k = current.getKeyDef(key);
        if(k!=null){
            if(k.command != null){
                LuaEngine.runLuaString(k.command);
            }
            if(k.nextNode != null){
                if(current.cursor != null)current.cursor.setActive(false);
                current = k.nextNode;
                if(current.cursor != null)current.cursor.setActive(true);
            }
            if(k.nextMenu!=null){
                //load new screen
                Screen s = ScreenStack.getScreen(k.nextMenu);
                if(s != null){
                    if(k.pop){
                        //replace current screen with the new one
                        ScreenStack.replace(s);
                    }else{
                        //pop up a new menu over this one
                        ScreenStack.push(s);
                    }
                }else{
                    System.err.println("ERROR: Screen named "+k.nextMenu+" does not exist");
                }
            }else if(k.pop){
                ScreenStack.pop();
            }
        }
    }
    
    //Initialize Lua linkages to the menu system
    /*public static void initializeMenuSystemLua(){
        LuaState L = LuaEngine.getLua();
        
        //register changeMenuString()
        
        //register changeMenuImage()
        
    }*/
    
    //Creates a new instance of a Menu from a file
    public GameMenu(String file){
        //initialize standard stuff
        items = new LinkedList<GameMenuItem>();
        itemtable = new Hashtable<String,GameMenuItem>();
        control = new Hashtable<String,ControlNode>();
        
        //open file
        File mconf = new File(file);
        Scanner sc = null;
        try{
            sc = new Scanner(mconf);
        }catch(FileNotFoundException e){
            //there was a problem, probably the file doesn't exist or is in the wrong spot
            System.err.println("Could not open "+file+"!");
            name = "Could Not Open File";
            x = 0;
            y = 0;
            this.addMenuItem(name,new GameMenuItem(0, 0, 5000, 5000, Color.red, true, 1.0f, true));
            this.addMenuItem(name,new GameMenuItem(0,20,"Could not open "+file+"!",new Font("serif",Font.BOLD,20),Color.black,1.0f,true));
            return;
        }
        
        //get name, x, and y
        if(sc.hasNext()){
            name = sc.next();
        }else{
            System.err.println(file + "is not properly formatted, no name");
            name = "File Not Properly Formatted";
        }
        if(sc.hasNextInt()){
            x = sc.nextInt();
        }else{
            System.err.println(file + "is not properly formatted, no x coordinate or not an integer");
            x = 0;
        }
        if(sc.hasNextInt()){
            y = sc.nextInt();
        }else{
            System.err.println(file + "is not properly formatted, no y coordinate or not an integer");
            y = 0;
        }
        
        //read each line
        sc.useDelimiter("\n");
        int linenum = 0;
        while(sc.hasNext()){
            String line = sc.next();
            if(sc.hasNext()){
                line = line.substring(0,line.length()-1);
            }
            
            System.out.println(line);
            
            //temp vars for items
            String itemname = null; //the item's name
            int itemtype = 0;       //the item's type - 0=none, 1=rectangle, 2=string, 3=luastring, 4=image, 5=imagestring, 6=luaimage
            int itemx = 0;
            int itemy = 0;
            float itemopac = 1.0f;
            boolean itemactive = true;
            String itemstring = null;   //the string used by 2-6
            int itemw = 0;
            int itemh = 0;
            Color itemcolor = null;     //used by 1-3
            boolean itemfill = true;
            String itemfont = null;
            String itemfmod = null;     //the font mod
            int itemsize = 12;          //font size
            
            //temp vars for nodes
            String nodename = null;
            String nodeitem = null;
            
            //temp vars for keys
            String keynode = null;
            String keykey = null;
            String keynewnode = null;
            String keycommand = null;
            String keymenu = null;
            boolean keypop = false;
            
            //split up the items in the line
            Scanner sc2 = new Scanner(line);
            boolean quote = false;
            String val = null;
            int mode = 0;           //0 = no mode, 1 = item mode, 2 = node mode, 3 = key mode
            int num = 0;            //the item number
            while(sc2.hasNext()){
                String mid = sc2.next();
                //System.out.println(mid);
                if(mid.charAt(0)=='"'){
                    quote = true;
                    mid = mid.substring(1);
                }
                if(mid.length()>0 && mid.charAt(mid.length()-1)=='"'){
                    quote = false;
                    mid = mid.substring(0,mid.length()-1);
                }
                if(quote){
                    if(val == null)val = mid + " ";
                    else val = val + mid + " ";
                    continue;
                }else{
                    if(val == null)val = mid;
                    else val = val + mid;
                }
                
                //System.out.println(val);
                
                //deal with the actual inputs
                if(mode == 0){
                    val = val.toLowerCase();
                    //this should be the next item/node/key
                    if(val.equals("item")){
                        mode = 1;
                    }else if(val.equals("node")){
                        mode = 2;
                    }else if(val.equals("key")){
                        mode = 3;
                    }else{
                        System.err.println(file + "is not properly formatted, no item/node/key tag at line "+linenum);
                        break;
                    }
                }else if(mode == 1){
                    if(num == 1){
                        //item name
                        itemname = val;
                    }else if(num == 2){
                        //type
                        val = val.toLowerCase();
                        if(val.equals("rectangle")){
                            itemtype = 1;
                        }else if(val.equals("string")){
                            itemtype = 2;
                        }else if(val.equals("luastring")){
                            itemtype = 3;
                        }else if(val.equals("image")){
                            itemtype = 4;
                        }else if(val.equals("luaimage")){
                            itemtype = 5;
                        }else{
                            System.err.println(file + "is not properly formatted, no item type at line "+linenum);
                            break;
                        }
                    }else if(num == 3){
                        //relative x pos
                        try{
                            itemx = Integer.parseInt(val);
                        }catch(NumberFormatException e){
                            System.err.println(file + "is not properly formatted, x is not an integer at line "+linenum);
                            break;
                        }
                    }else if(num == 4){
                        //relative y pos
                        try{
                            itemy = Integer.parseInt(val);
                        }catch(NumberFormatException e){
                            System.err.println(file + "is not properly formatted, y is not an integer at line "+linenum);
                            break;
                        }
                    }else if(num == 5){
                        //opacity
                        try{
                            itemopac = Float.parseFloat(val);
                        }catch(NumberFormatException e){
                            System.err.println(file + "is not properly formatted, opacity is not a number at line "+linenum);
                            break;
                        }
                    }else if(num == 6){
                        //active
                        itemactive = Boolean.parseBoolean(val);
                    }else{
                        if(itemtype == 1){
                            //rectangle
                            if(num == 7){
                                //width
                                try{
                                    itemw = Integer.parseInt(val);
                                }catch(NumberFormatException e){
                                    System.err.println(file + "is not properly formatted, width is not an integer at line "+linenum);
                                    break;
                                }
                            }else if(num == 8){
                                //height
                                try{
                                    itemh = Integer.parseInt(val);
                                }catch(NumberFormatException e){
                                    System.err.println(file + "is not properly formatted, height is not an integer at line "+linenum);
                                    break;
                                }
                            }else if(num == 9){
                                //color
                                int color;
                                try{
                                    color = Integer.parseInt(val,16);
                                }catch(NumberFormatException e){
                                    System.err.println(file + "is not properly formatted, color is not a hex integer at line "+linenum);
                                    break;
                                }
                                itemcolor = new Color(color);
                            }else if(num == 10){
                                //fill
                                itemfill = Boolean.parseBoolean(val);
                            }
                        }else if(itemtype > 1 && itemtype < 4){
                            //string
                            if(num == 7){
                                //string
                                itemstring = val;
                            }else if(num == 8){
                                //font name
                                itemfont = val;
                            }else if(num == 9){
                                //font mod
                                itemfmod = val;
                            }else if(num == 10){
                                //size
                                try{
                                    itemsize = Integer.parseInt(val);
                                }catch(NumberFormatException e){
                                    System.err.println(file + "is not properly formatted, font size is not an integer at line "+linenum);
                                    break;
                                }
                            }else if(num == 11){
                                //color
                                int color;
                                try{
                                    color = Integer.parseInt(val,16);
                                }catch(NumberFormatException e){
                                    System.err.println(file + "is not properly formatted, color is not a hex integer at line "+linenum);
                                    break;
                                }
                                itemcolor = new Color(color);
                            }
                        }else if(itemtype > 3){
                            //image
                            if(num == 7){
                                itemstring = val;
                            }
                        }
                    }
                }else if(mode == 2){
                    //node
                    if(num == 1){
                        //name
                        nodename = val;
                    }else if(num == 2){
                        //item
                        nodeitem = val;
                    }
                }else if(mode == 3){
                    //key
                    if(num == 1){
                        //node
                        keynode = val;
                    }else if(num == 2){
                        //key
                        keykey = val;
                    }else if(num == 3){
                        //newnode
                        keynewnode = val;
                    }else if(num == 4){
                        //command
                        keycommand = val;
                    }else if(num == 5){
                        //menu
                        keymenu = val;
                    }else if(num == 6){
                        //pop
                        keypop = Boolean.parseBoolean(val);
                    }
                }
                
                num++;
                val = null;
            }
            
            //actually create the new item
            if(mode == 1){
                if(itemtype == 1){
                    //rectangle
                    this.addMenuItem(itemname,new GameMenuItem(itemx, itemy, itemw, itemh, itemcolor, itemfill, itemopac, itemactive));
                }else if(itemtype == 2){
                    //string
                    itemfmod = itemfmod.toLowerCase();
                    Font itemf = null;
                    if(itemfmod.equals("bold")){
                        itemf = new Font(itemfont,Font.BOLD,itemsize);
                    }else if(itemfmod.equals("italic")){
                        itemf = new Font(itemfont,Font.ITALIC,itemsize);
                    }else{
                        itemf = new Font(itemfont,Font.PLAIN,itemsize);
                    }
                    this.addMenuItem(itemname,new GameMenuItem(itemx, itemy, new DisplayText(itemstring,itemf,itemcolor), itemopac, itemactive));
                }else if(itemtype == 3){
                    //luastring
                    itemfmod = itemfmod.toLowerCase();
                    Font itemf = null;
                    if(itemfmod.equals("bold")){
                        itemf = new Font(itemfont,Font.BOLD,itemsize);
                    }else if(itemfmod.equals("italic")){
                        itemf = new Font(itemfont,Font.ITALIC,itemsize);
                    }else{
                        itemf = new Font(itemfont,Font.PLAIN,itemsize);
                    }
                    this.addMenuItem(itemname,new GameMenuItem(itemx, itemy, new DisplayLuaText(itemstring,itemf,itemcolor), itemopac, itemactive));
                }else if(itemtype == 4){
                    //image
                    this.addMenuItem(itemname,new GameMenuItem(itemx, itemy, new DisplayStringImage(itemstring), itemopac, itemactive));
                }else if(itemtype == 5){
                    //luaimage
                    this.addMenuItem(itemname,new GameMenuItem(itemx, itemy, new DisplayLuaImage(itemstring), itemopac, itemactive));
                }
            }else if(mode == 2){
                GameMenuItem gmi = null;
                if(!(nodeitem.toLowerCase().equals("null"))){
                    gmi = this.getMenuItem(nodeitem);
                }
                //System.out.println("Control node registering item "+gmi+" named "+nodeitem);
                this.addControlNode(nodename,new ControlNode(gmi));
            }else if(mode == 3){
                //System.out.println("node = "+keynode);
                ControlNode pnode = this.getControlNode(keynode);
                if(pnode != null){
                    if(keykey != null){
                        ControlNode knn = null;
                        if(!(keynewnode.toLowerCase().equals("null"))){
                            knn = this.getControlNode(keynewnode);
                            if(knn == null){
                                System.err.println("Control node "+keynewnode+" is not registered at line "+linenum);
                            }
                        }
                        if(keycommand.toLowerCase().equals("null"))keycommand = null;
                        if(keymenu.toLowerCase().equals("null"))keymenu = null;
                        
                        //System.out.println("Registering "+knn+" "+keycommand+" "+keymenu+" "+keypop);
                        
                        KeyDef key = new KeyDef(knn,keycommand,keymenu,keypop);
                        pnode.addKeyDef(keykey,key);
                    }else{
                        System.err.println("No key specified at line "+linenum);
                    }
                }else{
                    System.err.println("Control node "+keynode+" is not registered at line "+linenum);
                }
            }
            
            linenum++;
        }
        
    }
    
}